﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Data.SqlClient;
using System.Windows.Forms;
using AccountingLibs;
using GuiUtilities;
using System.Threading;
using CustomControls;

namespace SynchronizeData
{
    public enum ChangeType
    {
        None = 0, Insert = 1, Update = 2, Delete = 3
    }

    public partial class FrmSynchronizedDbs : BasicForms.FrmClose
    {
        public FrmSynchronizedDbs()
        {
            InitializeComponent();
        }
        #region Singleton 
        private static FrmSynchronizedDbs form;
        public static FrmSynchronizedDbs Instance
        {
            get
            {
                if (form == null)
                {
                    form = new FrmSynchronizedDbs();
                }
                return form;
            }
        }
        #endregion
        SqlDataAdapter _DataAdapter = new SqlDataAdapter();
        DataTable _DataTableSynInfo1 = new DataTable();
        DataTable _DataTableSynInfo2 = new DataTable();
        string _ErrorMessage = "";
        string _CaptionInShowErrorMessage = "Lỗi đồng bộ";
        #region ConnectionString1
        string _ConnectionString1 = "";
        public string ConnectionString1
        {
            get
            {
                _ConnectionString1 = "Data Source=" + txtSQLServer1.Text.Trim() +
                                            ";initial catalog=" + cmbDBName1.Text.Trim() +
                                            ";User ID=" + txtDBUserName1.Text.Trim() +
                                            ";PWD=" + txtDBPassword1.Text;
                LocalSettings.HeThong.ConnectString1 = _ConnectionString1;
                return _ConnectionString1;
            }
        }
        #endregion
        #region ConnectionString2
        string _ConnectionString2 = "";
        public string ConnectionString2
        {
            get
            {
                _ConnectionString2 = "Data Source=" + txtSQLServer2.Text.Trim() +
                                               ";initial catalog=" + cmbDBName2.Text.Trim() +
                                               ";User ID=" + txtDBUserName2.Text.Trim() +
                                               ";PWD=" + txtDBPassword2.Text;
                LocalSettings.HeThong.ConnectString2 = _ConnectionString2;
                return _ConnectionString2;
            }
        }

        #endregion
        public string TenCuaHang1
        {
            get
            {
                if (cmbStoreName1.EditValue != null)
                {
                    return (string)cmbStoreName1.Text.Trim();
                }
                else
                {
                    return "";
                }
            }
        }
        public string TenCuaHang2
        {
            get
            {
                if (cmbStoreName2.EditValue != null)
                {
                    return (string)cmbStoreName2.Text.Trim();
                }
                else
                {
                    return "";
                }
            }
        }

        private void FrmSynchronizedDbs_Load(object sender, EventArgs e)
        {
            try
            {
                if (LocalSettings.HeThong == null)
                {
                    LocalSettings.HeThong = new LocalSettings();
                }
                else
                {
                    FrmProgressBar.StartShowProgress();
                    FrmProgressBar.Status = "Chương trình đang cấu hình các thông số. Xin vui lòng chờ ít phút";
                    txtDBPassword1.Text = LocalSettings.HeThong.DB_PASS;
                    txtDBUserName1.Text = LocalSettings.HeThong.DB_UID;
                    txtSQLServer1.Text = LocalSettings.HeThong.DB_Server;

                    txtDBPassword2.Text = LocalSettings.HeThong.DB_PASS2;
                    txtDBUserName2.Text = LocalSettings.HeThong.DB_UID2;
                    txtSQLServer2.Text = LocalSettings.HeThong.DB_Server2;

                    numericChuKyDongBo.Text = LocalSettings.HeThong.ChuKyDongBo.ToString();
                    chkbAutoSyn.Checked = LocalSettings.HeThong.TuDongDongBo;
                    labelLastUpdate.Text = Convert.ToString(LocalSettings.HeThong.LastUpdate);

                    GetListOfDBNameInServer(ConnectionString1, true);
                    GetListOfDBNameInServer(ConnectionString2, false);
                    GetListOfStoreName(ConnectionString1, true);
                    GetListOfStoreName(ConnectionString2, false);

                    timer.Start();
                    timer.Interval = 60000;// dung 60s xem
                    timer.Tick += new System.EventHandler(timer_Tick);

                    SetGui();
                    FrmProgressBar.FinishShowProgress();
                }
                Use_Notify();
            }
            catch (Exception ex)
            {
            }
        }

        private void GetListOfDBNameInServer(string connectionString, bool isTrungTam)
        {
            using (SqlConnection con = new SqlConnection())
            {
                con.ConnectionString = connectionString;
                DataTable dt = new DataTable();

                try
                {
                    con.Open();
                    SqlCommand cmd = con.CreateCommand();
                    cmd.CommandText = string.Format("SELECT Name FROM master.dbo.sysdatabases ORDER BY Name");
                    SqlDataAdapter _DataAdapter = new SqlDataAdapter(cmd);
                    dt.Clear();
                    _DataAdapter.Fill(dt);
                    if (isTrungTam)
                    {
                        cmbDBName1.DataSource = dt.DefaultView;
                        cmbDBName1.ValueColumn = "Name";
                        cmbDBName1.AddVisibleColumn("Name", "Tên CSDL");
                        cmbDBName1.DisplayColumn = "Name";
                        cmbDBName1.EditValue = LocalSettings.HeThong.DB_Name;
                    }
                    else
                    {
                        cmbDBName2.DataSource = dt.DefaultView;
                        cmbDBName2.ValueColumn = "Name";
                        cmbDBName2.AddVisibleColumn("Name", "Tên CSDL");
                        cmbDBName2.DisplayColumn = "Name";
                        cmbDBName2.EditValue = LocalSettings.HeThong.DB_Name2;
                    }
                    
                }
                catch (Exception ex)
                {
                }
                finally
                {
                    FrmProgressBar.FinishShowProgress();
                    if (con.State == ConnectionState.Open) con.Close();
                }
            }
        }      //Lấy tên các CSDL từ 2 Server về
        public void GetListOfStoreName(string connectionString, bool isTrungTam)
        {
            using (SqlConnection con = new SqlConnection())
            {
                con.ConnectionString = connectionString;
                DataTable listStoreName = new DataTable();
                SqlDataAdapter da = new SqlDataAdapter();
                try
                {
                    con.Open();
                    SqlCommand cmd = con.CreateCommand();
                    try
                    {
                        cmd.CommandText = "SELECT * FROM Store";
                        da.SelectCommand = cmd;
                        DataTable dvStore = new DataTable();
                        da.Fill(dvStore);

                        if (dvStore.Rows.Count <= 0 && cmbDBName1.Text != "" && cmbDBName2.Text != "")
                        {
                            if(isTrungTam)
                                MessageBox.Show("Lỗi CSDL Trung tâm.\nKhông có thông tin cửa hàng nào trong CSDL Trung tâm.\nBạn cần nhập đầy đủ thông số trước khi chạy chương trình đồng bộ.");
                            else
                                MessageBox.Show("Lỗi CSDL Trạm.\nKhông có thông tin cửa hàng nào trong CSDL Trạm.\nBạn cần nhập đầy đủ thông số trước khi chạy chương trình đồng bộ.");
                        }
                        else
                        {
                            if (isTrungTam)
                            {
                                if (LocalSettings.HeThong.StoreName1 != "")
                                {
                                    cmbStoreName1.DataSource = dvStore.DefaultView;
                                    cmbStoreName1.DisplayColumn = "Name";
                                    cmbStoreName1.ValueColumn = "Name";
                                    cmbStoreName1.AddVisibleColumn("StoreID", "Mã cửa hàng");
                                    cmbStoreName1.AddVisibleColumn("Name", "Tên cửa hàng");

                                    cmbStoreName1.EditValue = LocalSettings.HeThong.StoreName1;
                                }
                                else
                                {
                                    cmbStoreName1.DataSource = dvStore.DefaultView;
                                    cmbStoreName1.DisplayColumn = "Name";
                                    cmbStoreName1.ValueColumn = "Name";
                                    cmbStoreName1.AddVisibleColumn("StoreID", "Mã cửa hàng");
                                    cmbStoreName1.AddVisibleColumn("Name", "Tên cửa hàng");
                                }
                            }
                            else
                            {
                                if (LocalSettings.HeThong.StoreName2 != "")
                                {
                                    cmbStoreName2.DataSource = dvStore.DefaultView;
                                    cmbStoreName2.DisplayColumn = "Name";
                                    cmbStoreName2.ValueColumn = "Name";
                                    cmbStoreName2.AddVisibleColumn("StoreID", "Mã cửa hàng");
                                    cmbStoreName2.AddVisibleColumn("Name", "Tên cửa hàng");

                                    cmbStoreName2.EditValue = LocalSettings.HeThong.StoreName2;
                                }
                                else
                                {
                                    cmbStoreName2.DataSource = dvStore.DefaultView;
                                    cmbStoreName2.DisplayColumn = "Name";
                                    cmbStoreName2.ValueColumn = "Name";
                                    cmbStoreName2.AddVisibleColumn("StoreID", "Mã cửa hàng");
                                    cmbStoreName2.AddVisibleColumn("Name", "Tên cửa hàng");
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                    }
                }
                catch (Exception ex)
                { 
                }
                finally
                {
                    if (con.State == ConnectionState.Open) con.Close();
                }
            }
        }      //Lấy tên các CSDL từ 2 Server về
        private bool CheckConnectServer(string connectionString, bool isTrungTam)
        {
            FrmProgressBar.StartShowProgress("Kiểm tra kết nối");
            using (SqlConnection con = new SqlConnection())
            {
                con.ConnectionString = connectionString;
                try
                {
                    con.Open();
                    return true;
                }
                catch (Exception ex)
                {
                    return false;
                }
                finally
                {
                    FrmProgressBar.FinishShowProgress();
                    if (con.State == ConnectionState.Open) con.Close();
                }
            }
        }       //Kiểm tra kết nối đến server
        private void Use_Notify()
        {
            if (CheckAutoSyn()) tựĐộngĐồngBộToolStripMenuItem.Checked = true;
            else tựĐộngĐồngBộToolStripMenuItem.Checked = false;

            notifyIcon.ContextMenuStrip = contextMenuStrip;
            notifyIcon.BalloonTipText = "Đồng bộ CSDL giữa các cửa hàng.";
            notifyIcon.BalloonTipTitle = "Chương trình đồng bộ";
            notifyIcon.ShowBalloonTip(1);
        }        //Hiển thị Notify nếu để ở chế độ minimaze
        private bool CheckAutoSyn()
        {
            if (chkbAutoSyn.Checked == true) return true;
            else return false;
        }      //Kiểm tra xem chọn chế độ tự động đồng bộ không
        public void SetGui()
        {
            string filterExp = string.Format("Ma = {0}", (int)LocalSettings.HeThong.ChieuDongBo);
            DataRow[] rows = FrmEditChieuDongBo.InitTableChieuDongBo().Select(filterExp);

            string caption = string.Format("Phiên bản: {0}. Chiều đồng bộ: {1}.", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version, rows[0]["DienGiai"]);
            foreach (Form openForm in Application.OpenForms)
            {
                if (openForm.Name == "FrmSynchronizedDbs") openForm.Text = caption;
            }
        }

        private void LoadSyninfoToMemory()
        {
            SqlConnection con1 = new SqlConnection(), con2 = new SqlConnection();
            con1.ConnectionString = ConnectionString1;
            con2.ConnectionString = ConnectionString2;
            try
            {
                con1.Open();
                con2.Open();
                SqlCommand cmd1 = con1.CreateCommand();
                SqlCommand cmd2 = con2.CreateCommand();

                cmd1.CommandText = string.Format("SELECT * FROM SynInfo WHERE StoreID IN (SELECT StoreID FROM Store WHERE Name = @a) ORDER BY SynInfoID");
                _DataAdapter.SelectCommand = cmd1;
                cmd1.Parameters.Clear();
                cmd1.Parameters.AddWithValue("a", TenCuaHang2);
                _DataTableSynInfo1.Clear();
                _DataAdapter.Fill(_DataTableSynInfo1);

                cmd2.CommandText = string.Format("SELECT * FROM SynInfo WHERE StoreID IN (SELECT StoreID FROM Store WHERE Name = @a) ORDER BY SynInfoID");
                _DataAdapter.SelectCommand = cmd2;
                cmd2.Parameters.Clear();
                cmd2.Parameters.AddWithValue("a", TenCuaHang1);
                _DataTableSynInfo2.Clear();
                _DataAdapter.Fill(_DataTableSynInfo2);
            }
            catch (Exception ex)
            {
                throw new Exception("Lỗi khi load dữ liệu bảng SynInfo" + ex.Message);
            }
        }       //Load SynInfo lên bộ nhớ để xử lý, có thể dùng để load lại khi cần
        private void ShowMessageAutoClose(string message, string caption, uint timerStopShowMessage)
        {
            try
            {
                if (WindowState == FormWindowState.Minimized)
                {
                    notifyIcon.BalloonTipText = message;
                    notifyIcon.BalloonTipTitle = caption;
                    notifyIcon.ShowBalloonTip(1);
                }
                else
                    if (CheckAutoSyn()) MessageBoxEx.Show(message, timerStopShowMessage);
                    else MessageBox.Show(message, caption);
            }
            catch (Exception ex)
            {
                throw new Exception("Lỗi menthod hiện thông báo: " + ex.Message);
            }
        }    
        private void NormalLifeConflictMaHang()
        {
            //Truyền connection vào không dùng được Transaction nên phải khởi tạo connnection mới trong menthod này
            SqlConnection conI = new SqlConnection(), conII = new SqlConnection();
            conI.ConnectionString = ConnectionString1;
            conII.ConnectionString = ConnectionString2;
            SqlCommand cmd1 = conI.CreateCommand();
            SqlCommand cmd2 = conII.CreateCommand();

            string storeID = "";
            string tableName = "";
            string tableID = "";
            string recordID = "";
            ChangeType changeType = ChangeType.None;

            DataRow[] rows1 = _DataTableSynInfo1.Select("TableName = 'VatTuHangHoa'");
            DataRow[] rows2 = _DataTableSynInfo2.Select("TableName = 'VatTuHangHoa'");
            try
            {
                conI.Open();
                conII.Open();

                /*Tất cả đều được chuẩn hóa theo CSDL Trung tâm*/
                #region Check các trường hợp gây xung đột dữ liệu từ Trung tâm xuống Trạm từ bảng VatTuHangHoa do Mã và ID gây ra
                foreach (DataRow row in rows1)
                {
                    try
                    {
                        storeID = row[1].ToString();
                        tableName = row[2].ToString();
                        tableID = tableName + "ID";
                        recordID = row[3].ToString();
                        changeType = (ChangeType)(Convert.ToInt32(row[4].ToString()));

                        try
                        {
                            SqlDataAdapter dataAdapterCheck = new SqlDataAdapter();
                            DataTable dataTableCheck = new DataTable();

                            //neu kieu changeType = update va ID nay khong co tren DB tram ==> chuyen thanh Insert
                            //phải check trường hợp này trước Insert vì Insert có nhiều thứ đặc biệt
                            if (changeType == ChangeType.Update)
                            {
                                dataTableCheck.Clear();
                                cmd2.Parameters.Clear();

                                cmd2.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                                dataAdapterCheck.SelectCommand = cmd2;
                                dataAdapterCheck.Fill(dataTableCheck);
                                if (dataTableCheck.Rows.Count == 0)
                                {
                                    changeType = ChangeType.Insert;
                                }
                            }
                            //neu kieu changeType = insert va ID nay da co tren DB tram
                            if (changeType == ChangeType.Insert)
                            {
                                dataTableCheck.Clear();
                                cmd2.Parameters.Clear();

                                cmd2.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                                dataAdapterCheck.SelectCommand = cmd2;
                                dataAdapterCheck.Fill(dataTableCheck);

                                if (dataTableCheck.Rows.Count != 0)    // Có ID bên CSDL Trạm rồi
                                {
                                    changeType = ChangeType.Update;
                                } 
                                else //Chưa có ID này bên CSDL Trạm trong bảng VatTuHangHoa
                                {
                                    dataTableCheck.Clear();

                                    //Lấy thông tin hàng từ CSDL Trung tâm
                                    cmd1.CommandText = string.Format("SELECT * FROM VatTuHangHoa WHERE ID = '{0}'", recordID);
                                    dataAdapterCheck.SelectCommand = cmd1;
                                    dataAdapterCheck.Fill(dataTableCheck);

                                    string idInTrungTam = dataTableCheck.Rows[0]["ID"].ToString();
                                    string maHangInTrungTam = dataTableCheck.Rows[0]["Ma"].ToString();
                                    string tenHangInTrungTam = dataTableCheck.Rows[0]["Ten"].ToString();

                                    //Xem thông tin hàng có  mã trên trong CSDL Trạm 
                                    dataTableCheck.Clear();

                                    cmd2.CommandText = string.Format("SELECT * FROM VatTuHangHoa WHERE Ma = '{0}'", maHangInTrungTam);
                                    dataAdapterCheck.SelectCommand = cmd2;
                                    dataAdapterCheck.Fill(dataTableCheck);

                                    if (dataTableCheck.Rows.Count != 0) //Tồn tại hàng có mã này rồi nhưng ID 2 bên khác nhau. Ta không thể Insert được mà phải chuẩn hóa lại
                                    {
                                        string idInTram = dataTableCheck.Rows[0]["ID"].ToString();
                                        string maHangInTram = dataTableCheck.Rows[0]["Ma"].ToString();
                                        string tenHangInTram = dataTableCheck.Rows[0]["Ten"].ToString();

                                        SqlTransaction transaction = conII.BeginTransaction();
                                        cmd2.Transaction = transaction;
                                        try
                                        {
                                            //replace ID và tên hàng của CSDL Trạm theo trung tâm dựa vào mã hàng
                                            cmd2.CommandText = string.Format("UPDATE VatTuHangHoa SET ID = '{0}', Ten = '{1}' WHERE Ma = '{2}'", idInTrungTam, tenHangInTrungTam, maHangInTram);
                                            cmd2.ExecuteNonQuery();
                                            cmd2.CommandText = string.Format("UPDATE KhoanMucChungTu SET VatTuHangHoa1ID = '{0}' WHERE VatTuHangHoa1ID = '{1}'", idInTrungTam, idInTram);
                                            cmd2.ExecuteNonQuery();
                                            cmd2.CommandText = string.Format("UPDATE TonKho SET VatTuHangHoaID = '{0}' WHERE VatTuHangHoaID = '{1}'", idInTrungTam, idInTram);
                                            cmd2.ExecuteNonQuery();

                                            //Thay ChangeType thành Update vào bảng SynInfo vào bảng SynInfo
                                            cmd2.CommandText = string.Format("UPDATE SynInfo SET ChangeType = 2 WHERE RecordID = '{0}'", idInTrungTam);
                                            cmd2.ExecuteNonQuery();

                                            transaction.Commit();
                                        }
                                        catch (SqlException sqlEx)
                                        {
                                            throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                                        }
                                        catch (Exception ex)
                                        {
                                            if (ex is CustomException) throw ex;
                                            else
                                            {
                                                throw new CustomException(ex.Message);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        catch (SqlException sqlEx)
                        {
                            throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                        }
                        catch (Exception ex)
                        {
                            if (ex is CustomException) throw ex;
                            else
                            {
                                throw new CustomException(ex.Message);
                            }
                        }
                    }
                    catch (SqlException sqlEx)
                    {
                        throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                    }
                    catch (Exception ex)
                    {
                        if (ex is CustomException) throw ex;
                        else
                        {
                            throw new CustomException(ex.Message);
                        }
                    }
                }
                #endregion

                #region Check các trường hợp gây xung đột dữ liệu từ Trạm lên Trung tâm từ bảng VatTuHangHoa do Mã và ID gây ra
                foreach (DataRow row in rows2)
                {
                    try
                    {
                        storeID = row[1].ToString();
                        tableName = row[2].ToString();
                        tableID = tableName + "ID";
                        recordID = row[3].ToString();

                        changeType = (ChangeType)(Convert.ToInt32(row[4].ToString()));

                        try
                        {
                            SqlDataAdapter dataAdapterCheck = new SqlDataAdapter();
                            DataTable dataTableCheck = new DataTable();

                            //neu kieu changeType = update va ID nay khong co tren DB tram ==> chuyen thanh Insert
                            //phải check trường hợp này trước Insert vì Insert có nhiều thứ đặc biệt
                            if (changeType == ChangeType.Update)
                            {
                                cmd1.Parameters.Clear();

                                cmd1.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                                dataAdapterCheck.SelectCommand = cmd1;
                                dataAdapterCheck.Fill(dataTableCheck);
                                if (dataTableCheck.Rows.Count == 0)
                                {
                                    changeType = ChangeType.Insert;
                                }
                            }

                            //neu kieu changeType = insert va ID nay _DataAdapter co tren DB tram ==> chuyen thanh Update
                            if (changeType != ChangeType.None)
                            {
                                cmd1.Parameters.Clear();

                                cmd1.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                                dataAdapterCheck.SelectCommand = cmd1;
                                dataAdapterCheck.Fill(dataTableCheck);

                                if (dataTableCheck.Rows.Count != 0)    // Có ID bên CSDL Trung tâm rồi
                                {
                                    //cmd2.CommandText = string.Format("UPDATE SynInfo SET ChangeType = 2 WHERE RecordID = '{0}'", idInTram);
                                    //cmd2.ExecuteNonQuery();
                                    //cmd2.CommandText = string.Format("UPDATE SynInfo SET RecordID = '{0}' WHERE RecordID = '{1}'", idInTrungTam, idInTram);
                                    //cmd2.ExecuteNonQuery();
                                    changeType = ChangeType.Update;

                                }
                                else //Chưa có ID bên CSDL Trung tâm trong bảng VatTuHangHoa
                                {
                                    cmd1.Parameters.Clear();
                                    cmd2.Parameters.Clear();
                                    dataTableCheck.Clear();

                                    //Lấy mã hàng từ CSDL Trạm, vì trạm phải theo trung tâm, mà trung tâm k có ID trên nên phải thông qua mã từ trạm
                                    cmd2.CommandText = string.Format("SELECT * FROM VatTuHangHoa WHERE ID = '{0}' ", recordID);
                                    dataAdapterCheck.SelectCommand = cmd2;
                                    dataAdapterCheck.Fill(dataTableCheck);
                                    if (dataTableCheck.Rows.Count > 0)
                                    {
                                        string maHangInTram = dataTableCheck.Rows[0]["Ma"].ToString();

                                        //Lấy thông tin từ CSDL Trung tâm
                                        dataTableCheck.Clear();

                                        cmd1.CommandText = string.Format("SELECT * FROM VatTuHangHoa WHERE Ma = '{0}' ", maHangInTram);
                                        dataAdapterCheck.SelectCommand = cmd1;
                                        dataAdapterCheck.Fill(dataTableCheck);

                                        string idInTrungTam = dataTableCheck.Rows[0]["ID"].ToString();
                                        string maHangInTrungTam = dataTableCheck.Rows[0]["Ma"].ToString();
                                        string tenHangInTrungTam = dataTableCheck.Rows[0]["Ten"].ToString();

                                        //Xem thông tin hàng có  mã trên trong CSDL Trạm 
                                        dataTableCheck.Clear();

                                        cmd2.CommandText = string.Format("SELECT * FROM VatTuHangHoa WHERE Ma = '{0}'", maHangInTrungTam);
                                        dataAdapterCheck.SelectCommand = cmd2;
                                        dataAdapterCheck.Fill(dataTableCheck);

                                        if (dataTableCheck.Rows.Count != 0) //Tồn tại hàng có mã này rồi nhưng ID 2 bên khác nhau. Ta không thể Insert được mà phải chuẩn hóa lại
                                        {
                                            string idInTram = dataTableCheck.Rows[0]["ID"].ToString();
                                            maHangInTram = dataTableCheck.Rows[0]["Ma"].ToString();
                                            string tenHangInTram = dataTableCheck.Rows[0]["Ten"].ToString();

                                            SqlTransaction transaction = conII.BeginTransaction();
                                            cmd2.Transaction = transaction;
                                            try
                                            {
                                                //replace ID và tên hàng của CSDL Trạm theo trung tâm dựa vào mã hàng
                                                cmd2.CommandText = string.Format("UPDATE VatTuHangHoa SET ID = '{0}' WHERE Ma = '{1}'", idInTrungTam, maHangInTram);
                                                cmd2.ExecuteNonQuery();
                                                cmd2.CommandText = string.Format("UPDATE KhoanMucChungTu SET VatTuHangHoa1ID = '{0}' WHERE VatTuHangHoa1ID = '{1}'", idInTrungTam, idInTram);
                                                cmd2.ExecuteNonQuery();
                                                cmd2.CommandText = string.Format("UPDATE TonKho SET VatTuHangHoaID = '{0}'  WHERE VatTuHangHoaID = '{1}'", idInTrungTam, idInTram);
                                                cmd2.ExecuteNonQuery();

                                                //Thay recordID mới,ChangeType thành Update vào bảng SynInfo vào bảng SynInfo
                                                cmd2.CommandText = string.Format("UPDATE SynInfo SET ChangeType = 2 WHERE RecordID = '{0}'", idInTram);
                                                cmd2.ExecuteNonQuery();
                                                cmd2.CommandText = string.Format("UPDATE SynInfo SET RecordID = '{0}' WHERE RecordID = '{1}'", idInTrungTam, idInTram);
                                                cmd2.ExecuteNonQuery();

                                                transaction.Commit();
                                            }
                                            catch (SqlException sqlEx)
                                            {
                                                throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                                            }
                                            catch (Exception ex)
                                            {
                                                if (ex is CustomException) throw ex;
                                                else
                                                {
                                                    throw new CustomException(ex.Message);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        catch (SqlException sqlEx)
                        {
                            throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                        }
                        catch (Exception ex)
                        {
                            if (ex is CustomException) throw ex;
                            else
                            {
                                throw new CustomException(ex.Message);
                            }
                        }
                    }
                    catch (SqlException sqlEx)
                    {
                        throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                    }
                    catch (Exception ex)
                    {
                        if (ex is CustomException) throw ex;
                        else
                        {
                            throw new CustomException(ex.Message);
                        }
                    }
                }
                #endregion
            }
            catch (SqlException sqlEx)
            {
                throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
            }
            catch (Exception ex)
            {
                if (ex is CustomException) throw ex;
                else
                {
                    throw new CustomException(ex.Message);
                }
            }
            finally
            {
                conI.Close();
                conII.Close();
            }
        }      //Chuẩn hóa Bảng VatTuHangHoa
        private void DelDataOrphansInSynInfo()
        {
            SqlConnection conI = new SqlConnection(), conII = new SqlConnection();
            conI.ConnectionString = ConnectionString1;
            conII.ConnectionString = ConnectionString2;
            SqlCommand cmd1 = conI.CreateCommand();
            SqlCommand cmd2 = conII.CreateCommand();
            int conChay = -1;
            string tableName = "";
            string tableID = tableName + "ID";
            string recordID = "";

            try
            {
                conI.Open();
                conII.Open();

                GuiUtilities.FrmProgressBar.StartShowProgress("Đang xóa những bản ghi cần đồng bộ nhưng dữ liệu không tồn tại ở cả 2 CSDL");
                #region Xóa những trường không tồn tại ở cả 2 CSDL Trạm và Trung tâm (bảng VatTuHangHoa)
                /*  Trường hợp này sinh ra do khi thay đổi 1 record nhưng lại sinh ra 2 record trong bảng SynInfo.
                    Nguyên nhân là do có thêm Trigger TraceTime để xem ngày giờ thay đổi
                    Khi chuẩn hóa thì thì chuẩn được dòng 1 sau đó ID đã bị thay đổi nên dòng 2 mồ côi. Cần xóa những dòng mồ côi này đi
                    Để đấy cũng không đồng bộ được mà ảnh hưởng đến hiển thị báo cáo */

                //Xử lý SynInfo Trung tâm
                conChay = 0;
                while (_DataTableSynInfo1.Rows.Count > conChay)  
                {
                    DataRow row = _DataTableSynInfo1.Rows[conChay];
                    conChay++;
                    tableName = row[2].ToString();
                    tableID = tableName + "ID";
                    recordID = row[3].ToString();

                    DataTable dataTableCheck = new DataTable();
                    try
                    {
                        //Query 2 CSDL xem có danh mục hàng giống trong bảng SynInfo không
                        if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                        {
                            cmd1.CommandText = string.Format("SELECT * FROM {0} WHERE {1} = '{2}'", tableName, tableID, recordID);
                        }
                        else
                        {
                            cmd1.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                        }
                        _DataAdapter.SelectCommand = cmd1;
                        _DataAdapter.Fill(dataTableCheck);

                        if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                        {
                            cmd2.CommandText = string.Format("SELECT * FROM {0} WHERE {1} = '{2}'", tableName, tableID, recordID);
                        }
                        else
                        {
                            cmd2.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                        }
                        _DataAdapter.SelectCommand = cmd2;
                        _DataAdapter.Fill(dataTableCheck);
                        //Không có bản ghi nào trong dataTableCheck thì xóa đi
                        if (dataTableCheck.Rows.Count == 0)
                        {
                            cmd1.CommandText = string.Format("DELETE FROM SynInfo WHERE RecordID = '{0}'", recordID);
                            cmd1.ExecuteNonQuery();
                        }
                    }
                    catch (SqlException sqlEx)
                    {
                        throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                    }
                    catch (Exception ex)
                    {
                        if (ex is CustomException) throw ex;
                        else
                        {
                            _ErrorMessage = string.Format("Lỗi xóa dữ liệu mồ côi tại CSDL Trung tâm: " + ex.Message);
                            throw new CustomException(_ErrorMessage);
                        }
                    }
                }
                //Xử lý SynInfo Trạm
                conChay = 0;
                while (_DataTableSynInfo1.Rows.Count > conChay)
                {
                    DataRow row = _DataTableSynInfo1.Rows[conChay];
                    conChay++;
                    recordID = row[3].ToString();

                    DataTable dataTableCheck = new DataTable();
                    try
                    {
                        //Query 2 CSDL xem có danh mục hàng giống trong bảng SynInfo không
                        if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                        {
                            cmd1.CommandText = string.Format("SELECT * FROM {0} WHERE {1} = '{2}'", tableName, tableID, recordID);
                        }
                        else
                        {
                            cmd1.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                        }
                        _DataAdapter.SelectCommand = cmd1;
                        _DataAdapter.Fill(dataTableCheck);

                        if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                        {
                            cmd2.CommandText = string.Format("SELECT * FROM {0} WHERE {1} = '{2}'", tableName, tableID, recordID);
                        }
                        else
                        {
                            cmd2.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                        }
                        _DataAdapter.SelectCommand = cmd2;
                        _DataAdapter.Fill(dataTableCheck);
                        //Không có bản ghi nào trong dataTableCheck thì xóa đi
                        if (dataTableCheck.Rows.Count == 0)
                        {
                            cmd2.CommandText = string.Format("DELETE FROM SynInfo WHERE RecordID = '{0}'", recordID);
                            cmd2.ExecuteNonQuery();
                        }
                    }
                    catch (SqlException sqlEx)
                    {
                        throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                    }
                    catch (Exception ex)
                    {
                        if (ex is CustomException) throw ex;
                        else
                        {
                            _ErrorMessage = string.Format("Lỗi xóa dữ liệu mồ côi tại CSDL Trạm: " + ex.Message);
                            throw new CustomException(_ErrorMessage);
                        }
                    }
                }
                #endregion
            }
            catch (SqlException sqlEx)
            {
                throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
            }
            catch (Exception ex)
            {
                if (ex is CustomException) throw ex;
                else
                {
                    throw new CustomException(ex.Message);
                }
            }
            finally
            {
                GuiUtilities.FrmProgressBar.FinishShowProgress();
                conI.Close();
                conII.Close();
            }
        }     //Xóa tat ca dữ liệu mồ côi do chuẩn hóa
        private void GetListOfColumnsForInsert(out string listOfColumns, out string values, SqlCommand cmd, DataTable dtTableSource)
        {
            cmd.Parameters.Clear();
            values = "";
            listOfColumns = "";
            try
            {
                foreach (DataColumn column in dtTableSource.Columns)
                {
                    if (column.ColumnName != "LastUpdated")
                    {
                        values = values + "@" + column.ColumnName + ", ";
                        listOfColumns = listOfColumns + column.ColumnName + ", ";
                        cmd.Parameters.AddWithValue("@" + column.ColumnName, dtTableSource.Rows[0][column.ColumnName]);
                    }
                }
                if (values.EndsWith(", ")) values = values.Substring(0, values.Length - 2);
                if (listOfColumns.EndsWith(", ")) listOfColumns = listOfColumns.Substring(0, listOfColumns.Length - 2);
            }
            catch (SqlException sqlEx)
            {
                throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
            }
            catch (Exception ex)
            {
                if (ex is CustomException) throw ex;
                else
                {
                    throw new CustomException(ex.Message);
                }
            }
        }
        private void GetListOfColumnsForUpdate(out string updateQuery, SqlCommand cmd, DataTable dtTableSource)
        {
            cmd.Parameters.Clear();
            updateQuery = "";
            
            try
            {
                foreach (DataColumn column in dtTableSource.Columns)
                {
                    if ((column.ColumnName != "LastUpdated") && (column.ColumnName != "ID"))
                    {
                        updateQuery = updateQuery + string.Format("{0} = @{0}, ", column.ColumnName);
                        cmd.Parameters.AddWithValue(column.ColumnName, dtTableSource.Rows[0][column.ColumnName]);
                    }
                }
                if (updateQuery.EndsWith(", ")) updateQuery = updateQuery.Substring(0, updateQuery.Length - 2);
            }
            catch (SqlException sqlEx)
            {
                throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
            }
            catch (Exception ex)
            {
                if (ex is CustomException) throw ex;
                else
                {
                    throw new CustomException(ex.Message);
                }
            }
        }

        public void SynData()
        {
            if (cmbStoreName1.Text != "" && cmbStoreName2.Text != "" && cmbStoreName1.Text != cmbStoreName2.Text)
            {
                SqlConnection con1 = new SqlConnection(), con2 = new SqlConnection();
                try
                {
                    con1.ConnectionString = ConnectionString1;
                    con2.ConnectionString = ConnectionString2;
                }
                catch (SqlException sqlEx)
                {
                    throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                }
                catch (Exception ex)
                {
                    if (ex is CustomException) throw ex;
                    else
                    {
                        _ErrorMessage = string.Format("Lỗi chuỗi kết nối: {0}", ex.Message);
                        throw new Exception(_ErrorMessage);
                    }
                }

                int countRecordsCanDongBoTrungTamDenTram = 0;
                int countRecordsCanDongBoTramDenTrungTam = 0;
                int countRecordsCanDongBo = 0;
                int countRecordsDaDongBoTTDenTram = 0;
                int countRecordsDaDongBoTramDenTT = 0;
                int conChay = 0;

                if (countRecordsCanDongBo >= 0)
                {
                    try
                    {
                        con1.Open();
                        con2.Open();

                        SqlCommand cmd1 = con1.CreateCommand();
                        SqlCommand cmd2 = con2.CreateCommand();

                        string synInfoID = "";
                        string storeID = "";
                        string tableName = "";
                        string tableID = "";
                        string recordID = "";
                        ChangeType changeType = ChangeType.None;
                        ChieuDongBo chieuDongBo = (ChieuDongBo)LocalSettings.HeThong.ChieuDongBo;

                        LoadSyninfoToMemory();

                        countRecordsCanDongBoTrungTamDenTram = _DataTableSynInfo1.Rows.Count;
                        countRecordsCanDongBoTramDenTrungTam = _DataTableSynInfo2.Rows.Count;
                        countRecordsCanDongBo = countRecordsCanDongBoTrungTamDenTram + countRecordsCanDongBoTramDenTrungTam;

                        FrmProgressBar.StartShowProgress();

                        if (countRecordsCanDongBo == 0)
                        {
                            FrmProgressBar.FinishShowProgress();
                            ShowMessageAutoClose("Không có bản ghi cần đồng bộ!", "Chương trình đồng bộ", 3500);
                            return;
                        }
                        else timer.Stop();

                        if(chieuDongBo == ChieuDongBo.HaiChieu || chieuDongBo == ChieuDongBo.TrungTamDenTram)
                        {
                            #region Dong bo tu CSDL Trung tam ==> CSDL Tram
                            countRecordsDaDongBoTTDenTram = 0;               //Bat dau dem
                            conChay = 0;
                            if (countRecordsCanDongBoTrungTamDenTram <= 0 && chieuDongBo == ChieuDongBo.TrungTamDenTram)
                            {
                                FrmProgressBar.FinishShowProgress();
                                ShowMessageAutoClose("Không có bản ghi cần đồng bộ!", "Chương trình đồng bộ", 3500);
                                return;
                            }
                            else
                            {
                                while (_DataTableSynInfo1.Rows.Count > conChay)        //Phải dùng while vì khi chuẩn hóa sẽ load lại dữ liệu sẽ không chạy foreach được
                                {
                                    FrmProgressBar.Status = "TT->Trạm " + conChay + " / " + countRecordsCanDongBoTrungTamDenTram + " | " + countRecordsCanDongBo;
                                    DataRow row = _DataTableSynInfo1.Rows[conChay];
                                    conChay++;
                                    try
                                    {
                                        synInfoID = row[0].ToString();
                                        storeID = row[1].ToString();
                                        tableName = row[2].ToString();
                                        tableID = tableName + "ID";
                                        recordID = row[3].ToString();
                                        changeType = (ChangeType)(Convert.ToInt32(row[4].ToString()));

                                        //DelDataOrphansInSynInfo(recordID, tableName, out countRecordsDataOrphansDeletedInTT, out countRecordsDataOrphansDeletedInTram);

                                        try
                                        {
                                            if (con1.State != ConnectionState.Open) con1.Open();
                                            if (con2.State != ConnectionState.Open) con2.Open();
                                            SqlDataAdapter dataAdapterCheck = new SqlDataAdapter();
                                            DataTable dataTableCheck = new DataTable();

                                            //Những trường hợp này hay gặp xử lý đơn giản để tăng tốc độ
                                            //Trường hợp phức tạp liên quan đến bảng VatTuHangHoa sẽ xử lý riêng
                                            #region Check xung đột dữ liệu dạng đơn giản
                                            //neu kieu changeType = insert va ID nay da co tren DB tram ==> chuyen thanh Update
                                            if (changeType == ChangeType.Insert)
                                            {
                                                dataTableCheck.Clear();
                                                cmd2.Parameters.Clear();
                                                if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                                                {
                                                    cmd2.CommandText = string.Format("SELECT * FROM {0} WHERE {1} = '{2}'", tableName, tableID, recordID);
                                                }
                                                else
                                                {
                                                    cmd2.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                                                }
                                                dataAdapterCheck.SelectCommand = cmd2;
                                                dataAdapterCheck.Fill(dataTableCheck);
                                                if (dataTableCheck.Rows.Count != 0)
                                                {
                                                    changeType = ChangeType.Update;
                                                }
                                            }

                                            //neu kieu changeType = update va ID nay khong co tren DB tram ==> chuyen thanh Insert
                                            if (changeType == ChangeType.Update)
                                            {
                                                dataTableCheck.Clear();
                                                cmd2.Parameters.Clear();
                                                if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                                                {
                                                    cmd2.CommandText = string.Format("SELECT * FROM {0} WHERE {1} = '{2}'", tableName, tableID, recordID);
                                                }
                                                else
                                                {
                                                    cmd2.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                                                }
                                                dataAdapterCheck.SelectCommand = cmd2;
                                                dataAdapterCheck.Fill(dataTableCheck);
                                                if (dataTableCheck.Rows.Count == 0)
                                                {
                                                    changeType = ChangeType.Insert;
                                                }
                                            }

                                            //lay thong tin tu Db trung tam
                                            if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                                            {
                                                cmd1.CommandText = string.Format("SELECT * FROM {0} WHERE {1} = '{2}'", tableName, tableID, recordID);
                                            }
                                            else
                                            {
                                                cmd1.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                                            }
                                            _DataAdapter.SelectCommand = cmd1;
                                            DataTable dtTableSource1 = new DataTable();
                                            dtTableSource1.Clear();
                                            _DataAdapter.Fill(dtTableSource1);
                                            cmd2.Parameters.Clear();
                                            #endregion

                                            #region Synchronize
                                            switch (changeType)
                                            {
                                                case ChangeType.Insert:
                                                    string values = "", listOfColumns = "";
                                                    try
                                                    {
                                                        if (dtTableSource1.Rows.Count > 0)
                                                        {
                                                            GetListOfColumnsForInsert(out listOfColumns, out values, cmd2, dtTableSource1);

                                                            cmd2.CommandText = string.Format("INSERT INTO {0}({1}) VALUES ({2})", tableName, listOfColumns, values);
                                                            cmd2.ExecuteNonQuery();

                                                        }
                                                        cmd1.CommandText = string.Format("DELETE FROM SynInfo WHERE RecordID = '{0}' AND StoreID = {1}", recordID, storeID);
                                                        cmd1.ExecuteNonQuery();
                                                        countRecordsDaDongBoTTDenTram++;
                                                    }
                                                    catch (SqlException sqlEx)
                                                    {
                                                        throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                                                    }
                                                    catch (Exception ex)
                                                    {
                                                        if (ex is CustomException) throw ex;
                                                        else
                                                        {
                                                            throw new CustomException(ex.Message);
                                                        }
                                                    }
                                                    break;

                                                case ChangeType.Update:
                                                    string updateQuery = "";
                                                    try
                                                    {
                                                        if (dtTableSource1.Rows.Count > 0)
                                                        {
                                                            GetListOfColumnsForUpdate(out updateQuery, cmd2, dtTableSource1);
                                                            if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                                                            {
                                                                cmd2.CommandText = string.Format("UPDATE {0} SET {1} WHERE {2} = '{3}'", tableName, updateQuery, tableID, recordID);
                                                            }
                                                            else
                                                            {
                                                                cmd2.CommandText = string.Format("UPDATE {0} SET {1} WHERE ID = '{2}'", tableName, updateQuery, recordID);
                                                            }
                                                            cmd2.ExecuteNonQuery();

                                                        }
                                                        cmd1.CommandText = string.Format("DELETE FROM SynInfo WHERE RecordID = '{0}' AND StoreID = {1}", recordID, storeID);
                                                        cmd1.ExecuteNonQuery();
                                                        countRecordsDaDongBoTTDenTram++;
                                                    }
                                                    catch (SqlException sqlEx)
                                                    {
                                                        throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                                                    }
                                                    catch (Exception ex)
                                                    {
                                                        if (ex is CustomException) throw ex;
                                                        else
                                                        {
                                                            throw new CustomException(ex.Message);
                                                        }
                                                    }
                                                    break;

                                                case ChangeType.Delete:
                                                    try
                                                    {
                                                        if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                                                        {
                                                            cmd2.CommandText = string.Format("DELETE FROM {0} WHERE {1} = '{2}'", tableName, tableID, recordID);
                                                        }
                                                        else
                                                        {
                                                            cmd2.CommandText = string.Format("DELETE FROM {0} WHERE ID = '{1}'", tableName, recordID);
                                                        }

                                                        cmd2.ExecuteNonQuery();
                                                        cmd1.CommandText = string.Format("DELETE FROM SynInfo WHERE RecordID = '{0}' AND StoreID = {1}", recordID, storeID);
                                                        cmd1.ExecuteNonQuery();
                                                        countRecordsDaDongBoTTDenTram++;
                                                    }
                                                    catch (SqlException sqlEx)
                                                    {
                                                        throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                                                    }
                                                    catch (Exception ex)
                                                    {
                                                        if (ex is CustomException) throw ex;
                                                        else
                                                        {
                                                            throw new CustomException(ex.Message);
                                                        }
                                                    }
                                                    break;
                                            }
                                            #endregion
                                        }
                                        catch (SqlException sqlEx)
                                        {
                                            throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                                        }
                                        catch (Exception ex)
                                        {
                                            if (ex is CustomException) throw ex;
                                            else
                                            {
                                                throw new CustomException(ex.Message);
                                            }
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        _ErrorMessage = ex.ToString();
                                        if (_ErrorMessage.Contains("Lỗi: mã hoặc khóa này đã tồn tại") && tableName == "VatTuHangHoa")
                                        {
                                            _ErrorMessage = string.Format("Có danh mục hàng cùng mã nhưng khác định danh (ID) gây xung đột khi đồng bộ.\nHãy ấn nút 'Chuẩn hóa' để chương trình tự sửa lỗi này.");
                                            ShowMessageAutoClose(_ErrorMessage, _CaptionInShowErrorMessage, 5000);
                                            return;
                                        }
                                        else GuiUtilities.FrmExceptionNotifier.ShowAndLog(ex, chkbAutoSyn.Checked, 5);
                                    }
                                }
                            }
                            #endregion
                        }

                        if (chieuDongBo == ChieuDongBo.HaiChieu || chieuDongBo == ChieuDongBo.TramDenTrungTam)
                        {
                            #region Dong bo tu CSDL Tram ==> CSDL Trung tam
                            countRecordsDaDongBoTramDenTT = 0;               //Đếm lại cho Tram -> TT
                            conChay = 0;
                            if (countRecordsCanDongBoTramDenTrungTam == 0 && chieuDongBo == ChieuDongBo.TramDenTrungTam)
                            {
                                FrmProgressBar.FinishShowProgress();
                                ShowMessageAutoClose("Không có bản ghi cần đồng bộ!", "Chương trình đồng bộ", 3500);
                                return;
                            }
                            else
                            {
                                while (_DataTableSynInfo2.Rows.Count > conChay)   //Phải dùng while vì khi chuẩn hóa sẽ load lại dữ liệu sẽ không chạy foreach được
                                {
                                    FrmProgressBar.Status = "Trạm->TT " + conChay + " / " + countRecordsCanDongBoTramDenTrungTam + " | " + countRecordsCanDongBo;
                                    DataRow row = _DataTableSynInfo2.Rows[conChay];
                                    conChay++;
                                    try
                                    {
                                        synInfoID = row[0].ToString();
                                        storeID = row[1].ToString();
                                        tableName = row[2].ToString();
                                        tableID = tableName + "ID";
                                        recordID = row[3].ToString();
                                        changeType = (ChangeType)(Convert.ToInt32(row[4].ToString()));
                                        //DelDataOrphansInSynInfo(recordID, tableName, out countRecordsDataOrphansDeletedInTT, out countRecordsDataOrphansDeletedInTram);
                                        try
                                        {
                                            if (con1.State != ConnectionState.Open) con1.Open();
                                            if (con2.State != ConnectionState.Open) con2.Open();
                                            SqlDataAdapter dataAdapterCheck = new SqlDataAdapter();
                                            DataTable dataTableCheck = new DataTable();

                                            //Những trường hợp này hay gặp xử lý đơn giản để tăng tốc độ
                                            //Trường hợp phức tạp liên quan đến bảng VatTuHangHoa sẽ xử lý riêng
                                            #region Check xung đột dữ liệu dạng đơn giản
                                            //neu kieu changeType = insert va ID nay da co tren DB tram ==> chuyen thanh Update
                                            if (changeType == ChangeType.Insert)
                                            {
                                                cmd1.Parameters.Clear();
                                                if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                                                {
                                                    cmd1.CommandText = string.Format("SELECT * FROM {0} WHERE {1} = '{2}'", tableName, tableID, recordID);
                                                }
                                                else
                                                {
                                                    cmd1.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                                                }
                                                dataAdapterCheck.SelectCommand = cmd1;
                                                dataAdapterCheck.Fill(dataTableCheck);
                                                if (dataTableCheck.Rows.Count != 0)
                                                {
                                                    changeType = ChangeType.Update;
                                                }
                                            }

                                            //neu kieu changeType = update va ID nay khong co tren DB tram ==> chuyen thanh Insert
                                            if (changeType == ChangeType.Update)
                                            {
                                                cmd1.Parameters.Clear();
                                                if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                                                {
                                                    cmd1.CommandText = string.Format("SELECT * FROM {0} WHERE {1} = '{2}'", tableName, tableID, recordID);
                                                }
                                                else
                                                {
                                                    cmd1.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                                                }

                                                dataAdapterCheck.SelectCommand = cmd1;
                                                dataAdapterCheck.Fill(dataTableCheck);
                                                if (dataTableCheck.Rows.Count == 0)
                                                {
                                                    changeType = ChangeType.Insert;
                                                }
                                            }
                                            #endregion

                                            #region Synchronize
                                            //lay thong tin tu Db Tram
                                            if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                                            {
                                                cmd2.CommandText = string.Format("SELECT * FROM {0} WHERE {1} = '{2}'", tableName, tableID, recordID);
                                            }
                                            else
                                            {
                                                cmd2.CommandText = string.Format("SELECT * FROM {0} WHERE ID = '{1}'", tableName, recordID);
                                            }
                                            _DataAdapter.SelectCommand = cmd2;
                                            DataTable dtTableSource2 = new DataTable();
                                            dtTableSource2.Clear();
                                            _DataAdapter.Fill(dtTableSource2);
                                            cmd1.Parameters.Clear();

                                            switch (changeType)
                                            {
                                                case ChangeType.Insert:
                                                    string values = "", listOfColumns = "";
                                                    try
                                                    {
                                                        if (dtTableSource2.Rows.Count > 0)
                                                        {
                                                            GetListOfColumnsForInsert(out listOfColumns, out values, cmd1, dtTableSource2);
                                                            cmd1.CommandText = string.Format("INSERT INTO {0}({1}) VALUES ({2})", tableName, listOfColumns, values);
                                                            cmd1.ExecuteNonQuery();
                                                        }
                                                        cmd2.CommandText = string.Format("DELETE FROM SynInfo WHERE RecordID = '{0}' AND StoreID = {1}", recordID, storeID);
                                                        cmd2.ExecuteNonQuery();
                                                        countRecordsDaDongBoTramDenTT++;
                                                    }
                                                    catch (SqlException sqlEx)
                                                    {
                                                        throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                                                    }
                                                    catch (Exception ex)
                                                    {
                                                        if (ex is CustomException) throw ex;
                                                        else
                                                        {
                                                            throw new CustomException(ex.Message);
                                                        }
                                                    }
                                                    break;

                                                case ChangeType.Update:
                                                    string updateQuery = "";
                                                    cmd1.Parameters.Clear();
                                                    try
                                                    {
                                                        if (dtTableSource2.Rows.Count > 0)
                                                        {
                                                            GetListOfColumnsForUpdate(out updateQuery, cmd1, dtTableSource2);
                                                            if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                                                            {
                                                                cmd1.CommandText = string.Format("UPDATE {0} SET {1} WHERE {2} = '{3}'", tableName, updateQuery, tableID, recordID);
                                                            }
                                                            else
                                                            {
                                                                cmd1.CommandText = string.Format("UPDATE {0} SET {1} WHERE ID = '{2}'", tableName, updateQuery, recordID);
                                                            }
                                                            cmd1.ExecuteNonQuery();

                                                        }
                                                        cmd2.CommandText = string.Format("DELETE FROM SynInfo WHERE RecordID = '{0}' AND StoreID = {1}", recordID, storeID);
                                                        cmd2.ExecuteNonQuery();
                                                        countRecordsDaDongBoTramDenTT++;
                                                    }
                                                    catch (SqlException sqlEx)
                                                    {
                                                        throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                                                    }
                                                    catch (Exception ex)
                                                    {
                                                        if (ex is CustomException) throw ex;
                                                        else
                                                        {
                                                            throw new CustomException(ex.Message);
                                                        }
                                                    }
                                                    break;

                                                case ChangeType.Delete:
                                                    try
                                                    {
                                                        if (tableName == "ChungTu" || tableName == "KhoanMucChungTu")
                                                        {
                                                            cmd1.CommandText = string.Format("DELETE FROM {0} WHERE {1} = '{2}'", tableName, tableID, recordID);
                                                        }
                                                        else
                                                        {
                                                            cmd1.CommandText = string.Format("DELETE FROM {0} WHERE ID = '{1}'", tableName, recordID);
                                                        }
                                                        cmd1.ExecuteNonQuery();
                                                        cmd2.CommandText = string.Format("DELETE FROM SynInfo WHERE RecordID = '{0}' AND StoreID = {1}", recordID, storeID);
                                                        cmd2.ExecuteNonQuery();
                                                        countRecordsDaDongBoTramDenTT++;
                                                    }
                                                    catch (SqlException sqlEx)
                                                    {
                                                        throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                                                    }
                                                    catch (Exception ex)
                                                    {
                                                        if (ex is CustomException) throw ex;
                                                        else
                                                        {
                                                            throw new CustomException(ex.Message);
                                                        }
                                                    }
                                                    break;
                                            }
                                            #endregion
                                        }
                                        catch (SqlException sqlEx)
                                        {
                                            throw new CustomException(CustomException.GetSqlExceptionMessage(sqlEx));
                                        }
                                        catch (Exception ex)
                                        {
                                            if (ex is CustomException) throw ex;
                                            else
                                            {
                                                throw new CustomException(ex.Message);
                                            }
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        _ErrorMessage = ex.ToString();
                                        if (_ErrorMessage.Contains("Lỗi: mã hoặc khóa này đã tồn tại") && tableName == "VatTuHangHoa")
                                        {
                                            _ErrorMessage = string.Format("Có danh mục hàng cùng mã nhưng khác định danh (ID) gây xung đột khi đồng bộ.\nHãy ấn nút 'Chuẩn hóa' để chương trình tự sửa lỗi này.");
                                            ShowMessageAutoClose(_ErrorMessage, _CaptionInShowErrorMessage, 5000);
                                            return;
                                        }
                                        else GuiUtilities.FrmExceptionNotifier.ShowAndLog(ex, chkbAutoSyn.Checked, 5);
                                    }
                                }
                            }
                            #endregion
                        }

                        timer.Start();  //phai dong bo xong moi chay tiep timer
                        AccountingLibs.LocalSettings.HeThong.LastUpdate = DateTime.Now;
                        labelLastUpdate.Text = Convert.ToString(LocalSettings.HeThong.LastUpdate);
                        FrmProgressBar.FinishShowProgress();
                        
                        int countTotalDaDongBo = countRecordsDaDongBoTTDenTram + countRecordsDaDongBoTramDenTT;
                        if ((countRecordsCanDongBo - countRecordsDaDongBoTTDenTram - countRecordsDaDongBoTramDenTT) == 0 && (countRecordsCanDongBo != 0))
                        {
                            _ErrorMessage = string.Format("Đã đồng bộ xong!\nĐược " + countTotalDaDongBo + " bản ghi.");
                            ShowMessageAutoClose(_ErrorMessage, "Chương trình đồng bộ", 7000);
                        }
                        else if (countRecordsCanDongBo != 0)
                        {
                            _ErrorMessage = string.Format("Chỉ đồng bộ được : " + countTotalDaDongBo + " / " + countRecordsCanDongBo + " bản ghi.");
                            ShowMessageAutoClose(_ErrorMessage, "Chương trình đồng bộ", 7000);
                        }
                    }
                    catch (Exception ex)
                    {
                        GuiUtilities.FrmExceptionNotifier.ShowAndLog(ex, chkbAutoSyn.Checked, 5);
                    }
                    finally
                    {
                        _DataTableSynInfo1.Clear();
                        _DataTableSynInfo2.Clear();
                        con1.Close();
                        con2.Close();
                        FrmProgressBar.FinishShowProgress();
                    }
                }
            }
            else
            {
                _ErrorMessage = string.Format("Thông tin 2 cửa hàng chưa đầy đủ hoặc tên trùng nhau");
                ShowMessageAutoClose(_ErrorMessage, _CaptionInShowErrorMessage, 7000);
            }
        }

        private void btnNormalLife_Click(object sender, EventArgs e)
        {
            GuiUtilities.FrmProgressBar.StartShowProgress();
            GuiUtilities.FrmProgressBar.Status = "Đang chuẩn hóa danh mục hàng gây xung đột giữa 2 CSDL";

            SqlConnection conI = new SqlConnection(ConnectionString1), conII = new SqlConnection(ConnectionString2);
            SqlCommand cmd1 = conI.CreateCommand(); SqlCommand cmd2 = conII.CreateCommand();
            try
            {
                LoadSyninfoToMemory();
                NormalLifeConflictMaHang();
                DelDataOrphansInSynInfo();
                LoadSyninfoToMemory();
            }
            catch (Exception ex)
            {
                GuiUtilities.FrmExceptionNotifier.ShowAndLog(ex, chkbAutoSyn.Checked, 5);
            }
            GuiUtilities.FrmProgressBar.FinishShowProgress();
        }
        private void timer_Tick(object sender, EventArgs e)
        {
            TimeSpan duration = DateTime.Now - AccountingLibs.LocalSettings.HeThong.LastUpdate;

            int doiSangPhut = Convert.ToInt32(numericChuKyDongBo.Text.ToString());

            try
            {
                if (duration.TotalMinutes >= doiSangPhut && CheckAutoSyn() && doiSangPhut != 0)
                {
                    timer.Stop();
                    btnSynchronize_Click(null, null);
                    SetGui();
                    timer.Start();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Không chạy tự đồng bộ theo chu kì được.\n Lỗi: " + ex.Message);
            }
        }
        private void chkbAutoSyn_CheckedChanged(object sender, EventArgs e)
        {
            LocalSettings.HeThong.TuDongDongBo = chkbAutoSyn.Checked;
            LocalSettings.HeThong.Save2File();
        }
        private void notifyIcon_DoubleClick(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized)
            {
                Show();
                WindowState = FormWindowState.Normal;
            }
            else
            {
                WindowState = FormWindowState.Minimized;
                FrmSynchronizedDbs_Resize_1(null, null);
            }
        }
        private void FrmSynchronizedDbs_Resize_1(object sender, EventArgs e)
        {
            if (FormWindowState.Minimized == WindowState) Hide();
        }
        private void bắtĐầuĐồngBộToolStripMenuItem_Click(object sender, EventArgs e)
        {
            btnSynchronize_Click(null, null);
        }
        private void đóngToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
        private void tựĐộngĐồngBộToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (tựĐộngĐồngBộToolStripMenuItem.Checked == true)
            {
                tựĐộngĐồngBộToolStripMenuItem.Checked = false;
                chkbAutoSyn.Checked = false;
            }
            else
            {
                tựĐộngĐồngBộToolStripMenuItem.Checked = true;
                chkbAutoSyn.Checked = true;
            }
        }
        private void hiệnToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Show();
            WindowState = FormWindowState.Normal;
        }
        private void button1_Click(object sender, EventArgs e)
        {
            if (CheckConnectServer(ConnectionString1, true))
            {
                GetListOfDBNameInServer(ConnectionString1, true);
                MessageBox.Show("Kết nối thành công");
            }
            else MessageBox.Show("Không kết nối thành công");
        }
        private void button2_Click(object sender, EventArgs e)
        {
            if (CheckConnectServer(ConnectionString2, false))
            {
                GetListOfDBNameInServer(ConnectionString2, false);
                MessageBox.Show("Kết nối thành công");
            }
            else MessageBox.Show("Không kết nối thành công");
        }
        private void cmbDBName1_EditValueChanged(object sender, EventArgs e)
        {
            GetListOfStoreName(ConnectionString1, true);
        }
        private void cmbDBName2_EditValueChanged(object sender, EventArgs e)
        {
            GetListOfStoreName(ConnectionString2, false);
        }
        private void btnSynchronize_Click(object sender, EventArgs e)
        {
            LocalSettings.HeThong.DB_Name = cmbDBName1.Text.Trim();
            LocalSettings.HeThong.DB_PASS = txtDBPassword1.Text;
            LocalSettings.HeThong.DB_UID = txtDBUserName1.Text.Trim();
            LocalSettings.HeThong.DB_Server = txtSQLServer1.Text.Trim();

            LocalSettings.HeThong.DB_Name2 = cmbDBName2.Text.Trim();
            LocalSettings.HeThong.DB_PASS2 = txtDBPassword2.Text;
            LocalSettings.HeThong.DB_UID2 = txtDBUserName2.Text.Trim();
            LocalSettings.HeThong.DB_Server2 = txtSQLServer2.Text.Trim();

            LocalSettings.HeThong.StoreName1 = cmbStoreName1.Text.Trim();
            LocalSettings.HeThong.StoreName2 = cmbStoreName2.Text.Trim();
            try
            {
                LocalSettings.HeThong.StoreID1 = (int)cmbStoreName1.EditValue;
                LocalSettings.HeThong.StoreID2 = (int)cmbStoreName2.EditValue;
            }
            catch
            {
            }

            LocalSettings.HeThong.ChuKyDongBo = Convert.ToInt32(numericChuKyDongBo.Text.ToString());
            LocalSettings.HeThong.TuDongDongBo = chkbAutoSyn.Checked;
            LocalSettings.HeThong.LastUpdate = DateTime.Now;

            LocalSettings.HeThong.Save2File();

            SynData();
        }
        private void thôngSốCửaHàngToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FrmAskPassword frm = new FrmAskPassword("FrmDanhSachCuaHang");
            frm.Show();
        }
        private void chiềuĐồngBộToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FrmEditChieuDongBo frm = new FrmEditChieuDongBo();
            frm.Show();
        }
        private void FrmSynchronizedDbs_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (MessageBox.Show("Bạn muốn đóng chương trình đồng bộ?", "Xác nhận", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
            {
                e.Cancel = true;
            }
            else
            {
                this.notifyIcon.Dispose();
            }
        }
        private void cácBảngCầnĐồngBộToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //FrmAskPassword frm = new FrmAskPassword("FrmEditTablesNeedSyn");
            //frm.Show();

            FrmEditTablesNeedSyn frm = new FrmEditTablesNeedSyn();
            frm.Show();
        }
    }
}
